#pragma once
#include "pthread.h"
#include <vector>
#include <queue>
#include <string>
#include <functional>

struct thread_
{
    pthread_t _tid;
    std::string _name;
};

template <typename T>
class thread_pool
{
    static const int default_num = 10;

private:
    void lock() { pthread_mutex_lock(&_mutex); }
    void unlock() { pthread_mutex_unlock(&_mutex); }
    void thread_sleep() { pthread_cond_wait(&_cond, &_mutex); }
    void thread_wakeup() { pthread_cond_signal(&_cond); }

    std::string get_thread_name(pthread_t tid)
    {
        for (const auto &e : _threads)
            if (e._tid == tid)
                return e._name;
        return "none";
    }

    //  对于类内函数，存在一个隐含的实参(this指针，为了解决这一个问题，需要使用static成员函数作为线程的函数)
    //  可是static无法使用类内成员，所以可以降this指针作为实参传递给routine函数
    void thread_routine()
    {
        while (true)
        {
            // 1. 获取数据
            lock();
            while (_tasks.empty())
                thread_sleep();
            T t = pop();
            unlock();
            // 2. 处理数据
            t();
        }
    }

    static void *thread_task(void *args)
    {
        thread_pool<T> *ptp = static_cast<thread_pool<T> *>(args);
        auto routine = std::bind(&thread_pool::thread_routine, ptp);
        routine();
        return nullptr;
    }

public:
    bool is_empty() { return _tasks.empty(); }

    void start()
    {
        int i = 1;
        for (auto &e : _threads)
        {

            e._name = "thread " + std::to_string(i++);
            pthread_create(&(e._tid), nullptr, thread_task, this);
        }
    }

    void push(const T &t)
    {
        lock();
        _tasks.push(t);
        unlock();
        thread_wakeup();
    }

    T pop()
    {
        T t = _tasks.front();
        _tasks.pop();
        unlock();
        return t;
    }

    static thread_pool<T> *get_instance()
    {
        // 只有第一次使用的时候需要加锁，可以使用双重控制
        if (nullptr == _ptp)
        {
            // _ptp也是一个全局变量，需要用互斥锁来维护
            pthread_mutex_lock(&_pool_mutex);
            if (nullptr == _ptp)
                // 我需要生成新的线程池
                _ptp = new thread_pool<T>;
            pthread_mutex_unlock(&_pool_mutex);
        }
        return _ptp;
    }

private:
    thread_pool<T>(const thread_pool<T> &) = delete;
    const thread_pool<T> &operator=(const thread_pool<T> &) = delete;
    thread_pool(int num = default_num)
        : _threads(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ~thread_pool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    std::vector<thread_> _threads;
    // 线程之间需要有同步关系, 用条件变量实现
    pthread_cond_t _cond;
    // 任务队列
    std::queue<T> _tasks;
    // 在操作任务队列时需要加锁
    pthread_mutex_t _mutex;
    static pthread_mutex_t _pool_mutex;
    static thread_pool<T> *_ptp;
};

template <typename T>
thread_pool<T> *thread_pool<T>::_ptp = nullptr;

template <typename T>
pthread_mutex_t thread_pool<T>::_pool_mutex = PTHREAD_MUTEX_INITIALIZER;